use super::{ByteReader, ByteRead, ByteResult, ByteError};

use bitvec::{prelude::*, macros::internal::funty::Integral};

pub struct BitReader<'a,R> {
    rest_byte:u8,
    start_position:usize,
    bits_num:usize,
    byte_reader:&'a mut ByteReader<R>
}

impl<'a,R:ByteRead> BitReader<'a,R> {
    pub fn new(byte_reader:&'a mut ByteReader<R>) -> Self {
        Self { byte_reader, rest_byte:0, start_position:8, bits_num:0 }
    }

    pub fn read_reverse_bits<I:Integral>(&mut self, num:usize) -> ByteResult<I> {
        if num == 0 { return Ok(Integral::ZERO); }
        self.bits_num += num;
        let need_bytes_num = (num + self.start_position + 7)/8;
        let mut buf = vec![0;need_bytes_num];
        buf[0] = self.rest_byte;
        self.byte_reader.read_to_bytes(&mut buf[1..])?;
        let bit_vec = (&buf as &[u8]).view_bits::<Msb0>();
        let start_position = self.start_position;
        let end_position = start_position + num;
        let slice = bit_vec.get(start_position..end_position).ok_or(ByteError::BitRange)?;
        self.rest_byte = buf[need_bytes_num - 1];
        self.start_position = end_position - (need_bytes_num - 1) * 8;
        Ok(slice.load_be())
    }

    pub fn read_reverse_padding(&mut self) -> ByteResult<()>{
        assert!(!self.bits_remaining());
        self.rest_byte = self.byte_reader.read_to_u8()?;
        self.start_position = self.rest_byte.leading_zeros() as usize + 1;
        self.bits_num += self.start_position;
        Ok(())
    }

    pub fn read_bits<I:Integral>(&mut self, num:usize) -> ByteResult<I> {
        if num == 0 { return Ok(Integral::ZERO); }
        self.bits_num += num;
        let need_bytes_num = (num + self.start_position + 7)/8;
        let mut buf = vec![0;need_bytes_num];
        buf[0] = self.rest_byte;
        self.byte_reader.read_to_bytes(&mut buf[1..])?;
        let bit_vec = (&buf as &[u8]).view_bits::<Lsb0>();
        let start_position = self.start_position;
        let end_position = start_position + num;
        let slice = bit_vec.get(start_position..end_position).ok_or(ByteError::BitRange)?;
        self.rest_byte = buf[need_bytes_num - 1];
        self.start_position = end_position - (need_bytes_num - 1) * 8;
        Ok(slice.load_le())
    }

    pub fn read_remain_bits(&mut self) -> ByteResult<u8> {
        let remain = 8 - self.start_position;
        self.start_position = remain;
        self.bits_num += remain;
        Ok(remain as u8)
    }

    pub fn bits_remaining(&self) -> bool {
        !self.start_position == 8
    }

    pub fn bits_num(&self) -> usize {
        self.bits_num
    }
}